x11: Implement popup surfaces
authorMatthias Clasen <mclasen@redhat.com>
Mon, 22 Apr 2019 15:22:33 +0000 (15:22 +0000)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 28 May 2019 20:25:14 +0000 (20:25 +0000)
Make them use o-r windows, and move
with their parent.

We do a sort-of ok job on stacking order
here - whenever the parent window gets a
ConfigureNotify, we just restack all popups
directly on top of their parent. This is good
enough to keep popups on top of their parent
while we drag it around, and it gets the popup
to disappear when raising another window on
top of the parent.

gdk/x11/gdkdisplay-x11.c
gdk/x11/gdkprivate-x11.h
gdk/x11/gdksurface-x11.c
gdk/x11/gdksurface-x11.h

index 95ca2211f35b7cdef1739017a259f79209a1ea12..62de7d39e9e775559a8d3d45fd80f4a0bb94cab4 100644 (file)
@@ -985,8 +985,12 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
            }
          if (!is_substructure)
            {
-             surface->x = event->configure.x;
-             surface->y = event->configure.y;
+              if (surface->x != event->configure.x ||
+                  surface->y != event->configure.y)
+                {
+                  surface->x = event->configure.x;
+                  surface->y = event->configure.y;
+                }
 
               if (surface_impl->unscaled_width != xevent->xconfigure.width ||
                   surface_impl->unscaled_height != xevent->xconfigure.height)
@@ -1007,6 +1011,8 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
                  if (surface->resize_count == 0)
                    _gdk_x11_moveresize_configure_done (display, surface);
                }
+
+              gdk_x11_surface_update_popups (surface);
            }
         }
       break;
index 05b8c1f7dfc81449ab9b83fd6592d37037c223fc..ff32ea7642e7d084e5da2cda5207995353f7d9df 100644 (file)
@@ -223,6 +223,8 @@ void _gdk_x11_cursor_display_finalize (GdkDisplay *display);
 
 void _gdk_x11_surface_register_dnd (GdkSurface *window);
 
+void gdk_x11_surface_update_popups (GdkSurface *surface);
+
 GdkDrag        * _gdk_x11_surface_drag_begin (GdkSurface          *window,
                                               GdkDevice          *device,
                                               GdkContentProvider *content,
index 0643948ec25554f6c7e9cb0950e94a47839aaa60..1d6dee093a2ad9a94f8cd6a54a037300d2e20f3c 100644 (file)
@@ -425,12 +425,20 @@ gdk_x11_surface_end_frame (GdkSurface *surface)
 static void
 gdk_x11_surface_finalize (GObject *object)
 {
+  GdkSurface *surface;
   GdkX11Surface *impl;
 
   g_return_if_fail (GDK_IS_X11_SURFACE (object));
 
+  surface = GDK_SURFACE (object);
   impl = GDK_X11_SURFACE (object);
 
+  if (surface->parent)
+    {
+      GdkX11Surface *parent_impl = GDK_X11_SURFACE (surface->parent);
+      parent_impl->popups = g_list_remove (parent_impl->popups, surface);
+    }
+
   if (impl->toplevel->in_frame)
     unhook_surface_changed (GDK_SURFACE (impl));
 
@@ -842,7 +850,8 @@ _gdk_x11_display_create_surface (GdkDisplay     *display,
   xattributes.colormap = gdk_x11_display_get_window_colormap (display_x11);
   xattributes_mask |= CWColormap;
 
-  if (surface->surface_type == GDK_SURFACE_TEMP)
+  if (surface->surface_type == GDK_SURFACE_TEMP ||
+      surface->surface_type == GDK_SURFACE_POPUP)
     {
       xattributes.save_under = True;
       xattributes.override_redirect = True;
@@ -899,6 +908,12 @@ _gdk_x11_display_create_surface (GdkDisplay     *display,
 
   gdk_surface_freeze_toplevel_updates (surface);
 
+  if (parent)
+    {
+      GdkX11Surface *parent_impl = GDK_X11_SURFACE (parent);
+      parent_impl->popups = g_list_prepend (parent_impl->popups, surface);
+    }
+
   return surface;
 }
 
@@ -1231,8 +1246,8 @@ gdk_x11_surface_hide (GdkSurface *surface)
 
 static inline void
 x11_surface_move (GdkSurface *surface,
-                 gint       x,
-                 gint       y)
+                  gint        x,
+                  gint        y)
 {
   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
 
@@ -1244,6 +1259,12 @@ x11_surface_move (GdkSurface *surface,
     {
       surface->x = x;
       surface->y = y;
+
+      if (surface->parent)
+        {
+          impl->offset_x = surface->x - surface->parent->x;
+          impl->offset_y = surface->y - surface->parent->y;
+        }
     }
 }
 
@@ -1283,10 +1304,10 @@ x11_surface_resize (GdkSurface *surface,
 
 static inline void
 x11_surface_move_resize (GdkSurface *surface,
-                        gint       x,
-                        gint       y,
-                        gint       width,
-                        gint       height)
+                         gint        x,
+                         gint        y,
+                         gint        width,
+                         gint        height)
 {
   GdkX11Surface *impl = GDK_X11_SURFACE (surface);
 
@@ -1314,6 +1335,12 @@ x11_surface_move_resize (GdkSurface *surface,
       surface->height = height;
 
       _gdk_x11_surface_update_size (GDK_X11_SURFACE (surface));
+
+      if (surface->parent)
+        {
+          impl->offset_x = surface->x - surface->parent->x;
+          impl->offset_y = surface->y - surface->parent->y;
+        }
     }
   else
     {
@@ -1324,11 +1351,11 @@ x11_surface_move_resize (GdkSurface *surface,
 
 static void
 gdk_x11_surface_move_resize (GdkSurface *surface,
-                            gboolean   with_move,
-                            gint       x,
-                            gint       y,
-                            gint       width,
-                            gint       height)
+                             gboolean    with_move,
+                             gint        x,
+                             gint        y,
+                             gint        width,
+                             gint        height)
 {
   if (with_move && (width < 0 && height < 0))
     x11_surface_move (surface, x, y);
@@ -1341,6 +1368,29 @@ gdk_x11_surface_move_resize (GdkSurface *surface,
     }
 }
 
+static void gdk_x11_surface_restack_toplevel (GdkSurface *surface,
+                                              GdkSurface *sibling,
+                                              gboolean    above);
+
+void
+gdk_x11_surface_update_popups (GdkSurface *parent)
+{
+  GdkX11Surface *impl = GDK_X11_SURFACE (parent);
+  GList *l;
+
+  for (l = impl->popups; l; l = l->next)
+    {
+      GdkX11Surface *popup_impl = l->data;
+      GdkSurface *popup = GDK_SURFACE (popup_impl);
+      int new_x = parent->x + popup_impl->offset_x;
+      int new_y = parent->y + popup_impl->offset_y;
+
+      if (new_x != popup->x || new_y != popup->y)
+        x11_surface_move (popup, new_x, new_y);
+      gdk_x11_surface_restack_toplevel (popup, parent, TRUE);
+    }
+}
+
 void
 _gdk_x11_surface_set_surface_scale (GdkSurface *surface,
                                  int scale)
@@ -1390,8 +1440,8 @@ gdk_x11_surface_raise (GdkSurface *surface)
 
 static void
 gdk_x11_surface_restack_toplevel (GdkSurface *surface,
-                                GdkSurface *sibling,
-                                gboolean   above)
+                                  GdkSurface *sibling,
+                                  gboolean    above)
 {
   XWindowChanges changes;
 
index 6ffdbf24e614474b3c8c2ff7aab25e46cd07eb64..c051d10d826597cdd97103baf3dafbdcf51d9dd9 100644 (file)
@@ -75,6 +75,11 @@ struct _GdkX11Surface
 #if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
   Damage damage;
 #endif
+
+  int offset_x;
+  int offset_y;
+
+  GList *popups;
 };
  
 struct _GdkX11SurfaceClass